package com.java.code.thread;

import lombok.SneakyThrows;
import org.junit.Test;

import java.util.concurrent.*;

public class JavaThread {

    /**
     * 创建线程
     *
     * @throws InterruptedException
     */
    @Test
    public void testThread1() throws InterruptedException {
        /**
         * 1 继承Thread
         */
        Thread thread1 = new CalcThread();
        thread1.start();

        /**
         * 2 继承Runnable
         * 相对于继承Thread 改变了单继承的缺点
         */
        Thread thread2 = new Thread(new CalcRunnable());
        thread2.start();

        /**
         * 3 继承Callable
         * 指定一个单线程池Executors.newSingleThreadExecutor()
         * 自始至终都是一个线程
         * 相对于Thread,Runnable带有返回值
         */
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        Future<Object> future = threadPool.submit(new CalcCallable());
        try {
            System.out.println("Callable==========" + future.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 自定义线程的任务执行完毕再继续
     *
     * @throws InterruptedException
     */
    @Test
    public void testThread7() throws InterruptedException {
        int count = 5;
        Thread[] threads = new Thread[count];
        final CountDownLatch latch = new CountDownLatch(count);
        for (int index = 0; index < count; index++) {
            final int threadIndex = index;
            threads[index] = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("自定义线程,当前线程name" + Thread.currentThread().getName() + "=======" + threadIndex);
                    latch.countDown();
                }
            });
            threads[index].start();
        }
        latch.await();
        System.out.println("所有的线程都执行完毕了!");
    }

    /**
     * 线程的顺序执行
     * 等一个线程执行完 再执行另一个线程
     *
     * @throws InterruptedException
     */
    @Test
    public void testJoin() throws InterruptedException {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int index = 0; index < 3; index++) {
                    System.out.println(Thread.currentThread().getName() + ":" + index);
                }
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    threadA.join();//threadB将CPU让给threadA执行 其实就是等待线程A执行完
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                for (int index = 0; index < 3; index++) {
                    System.out.println(Thread.currentThread().getName() + ":" + index);
                }
            }
        });

        threadA.start();
        threadB.start();

        Thread.sleep(10000);

    }

    /**
     * 设置一个线程和另一个线程之间执行得顺序交叉有序
     * 比如 thread0 打印 1 thread1 打印 123 然后thread0 继续打印 2 3
     * <p>
     * 1) 先调用synchronized 因为thread0先启动 thread0先拿到锁 thread1等待
     * 2) lock.wait();会释放当前锁将cpu控制权交出去 这时候thread1拿到锁
     * 3) thread1全部执行完之后调用lock.notifyAll();唤醒正在wait的thread0
     * 4) thread0把流程执行完
     *
     * @throws InterruptedException
     */
    private static Object lock = new Object();

    @Test
    public void testWait() throws InterruptedException {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName() + ":1");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":2");
                    System.out.println(Thread.currentThread().getName() + ":3");
                }
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName() + ":1");
                    System.out.println(Thread.currentThread().getName() + ":2");
                    System.out.println(Thread.currentThread().getName() + ":3");
                    lock.notifyAll();
                }
            }
        });

        threadA.start();
        threadB.start();

        Thread.sleep(10000);
    }

    /**
     * 线程A 等待线程B执行结束 返回结果
     * 如果线程B 等待3秒不返回结果 那么线程A返回一个默认的结果
     */
    @Test
    public void testExecute() throws Exception {

        Thread threadA = new Thread(() -> {
            //实例化一个B任务
            FutureTask task = new FutureTask(new Callable() {
                @Override
                public Object call() throws Exception {
                    Thread.sleep(4000);
                    return "线程B返回";
                }
            });
            //将任务放到线程B里面 让线程B去执行
            Thread threadB = new Thread(task);
            threadB.start();
            //task.get()主线程等待任务执行完成
            //阻塞返回值是FutureTask的一个弊端,会一直while(true)等待任务完成会导致CPU资源飙升
            String result = "";
            try {
                result = String.valueOf(task.get(3, TimeUnit.SECONDS));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
            if (result == "") {
                //通知终止线程
                threadB.interrupt();
                System.out.println("线程A返回");
            } else {
                System.out.println(result);
            }
        });
        threadA.start();

        Thread.sleep(10 * 1000);
    }

    /**
     * 信号量
     * 只允许两个线程同时运行
     */
    @Test
    public void testSemaphore() throws InterruptedException {
        Semaphore semaphore = new Semaphore(2);
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        System.out.println("线程:" + Thread.currentThread().getName() + "获得许可:" + index);
                        TimeUnit.SECONDS.sleep(1);
                        semaphore.release();
                        System.out.println("允许TASK个数：" + semaphore.availablePermits());
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            });
        }
        // 不再提交新的任务
        executorService.shutdown();
        Thread.sleep(20 * 1000);
    }


    public class CalcCallable implements Callable<Object> {

        @Override
        public Object call() throws Exception {
            return Thread.currentThread().getName();
        }
    }

    public class CalcRunnable implements Runnable {

        @Override
        public void run() {
            System.out.println("Runnable==========" + Thread.currentThread().getName());
        }
    }

    public class CalcThread extends Thread {
        @Override
        public void run() {
            System.out.println("Thread==========" + Thread.currentThread().getName());
        }
    }
}


